using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace DictGen
{
    /* 
     * Master Collation Table from CRULP
     * CURLP has published this table at http://www.crulp.org/software/langproc/urducollation.htm
     * as part of their collation utility.
     * 
     * This class implements IComparer<string> interface to help sort the entries 
     * correctly in SortedDictionary<string, object>. The comparer can be used 
     * in any Generic collection class that uses this interface
     * 
     * Kashif Aqeel Aug 3, 2008
     * 
    [200C]			// ZERO WIDTH NON-JOINER
    [0600]			// ARABIC NUMBER SIGN
    [0601]			// ARABIC SIGN SANAH
    [0602]			// ARABIC FOOTNOTE MARKER
    [0603]			// ARABIC SIGN SAFHA
    [0615]			// ARABIC SMALL HIGH TAH
    [060C]			// ARABIC COMMA
    [060D]			// ARABIC DATE SEPARATOR
    [066B]			// ARABIC DECIMAL SEPARATOR
    [066C]			// ARABIC THOUSANDS SEPARATOR
    [061F]			// ARABIC QUESTION MARK
    [061B]			// ARABIC SEMICOLON
    [06D4]			// ARABIC FULL STOP
    [066A]			// ARABIC PERCENT SIGN
    [060E]			// ARABIC POETIC VERSE SIGN
    [060F]			// ARABIC SIGN MISRA
    [0610]			// ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM
    [0611]			// ARABIC SIGN ALAYHE ASSALLAM
    [0613]			// ARABIC SIGN RADI ALLAHOU ANHU
    [0612]			// ARABIC SIGN RAHMATULLAH ALAYHE
    [0614]			// ARABIC SIGN TAKHALLUS
    [0652]			// ARABIC SUKUN
    [064E]			// ARABIC FATHA
    [0650]			// ARABIC KASRA
    [064F]			// ARABIC DAMMA
    [0670]			// ARABIC LETTER SUPERSCRIPT ALEF
    [0656]			// ARABIC SUBSCRIPT ALEF
    [0657]			// ARABIC INVERTED DAMMA 
    [064B]			// ARABIC FATHATAN
    [064D]			// ARABIC KASRATAN
    [064C]			// ARABIC DAMMATAN
    [0654]			// ARABIC HAMZA ABOVE
    [0651]			// ARABIC SHADDA
    [0658]			// ARABIC MARK NOON GHUNNA
    [0653]			// ARABIC MADDAH ABOVE
    [06F0]			// EXTENDED ARABIC-INDIC DIGIT ZERO
    [06F1]			// EXTENDED ARABIC-INDIC DIGIT ONE
    [06F2]			// EXTENDED ARABIC-INDIC DIGIT TWO
    [06F3]			// EXTENDED ARABIC-INDIC DIGIT THREE
    [06F4]			// EXTENDED ARABIC-INDIC DIGIT FOUR
    [06F5]			// EXTENDED ARABIC-INDIC DIGIT FIVE
    [06F6]			// EXTENDED ARABIC-INDIC DIGIT SIX
    [06F7]			// EXTENDED ARABIC-INDIC DIGIT SEVEN
    [06F8]			// EXTENDED ARABIC-INDIC DIGIT EIGHT
    [06F9]			// EXTENDED ARABIC-INDIC DIGIT NINE
    [0627]			// ARABIC LETTER ALEF
    [0622]			// ARABIC LETTER ALEF WITH MADDA ABOVE
    [0623]			// ARABIC LETTER ALEF WITH HAMZA ABOVE                      Added by Kashif 
    [0627,0653]		// ARABIC LETTER ALEF   + ARABIC MADDAH ABOVE
    [0628]			// ARABIC LETTER BEH
    [0628,06BE]		// ARABIC LETTER BEH    + ARABIC LETTER HEH DOCHASHMI
    [067E]			// ARABIC LETTER PEH
    [067E,06BE]		// ARABIC LETTER PEH    + ARABIC LETTER HEH DOCHASHMI
    [062A]			// ARABIC LETTER TEH
    [062A,06BE]		// ARABIC LETTER THE    + ARABIC LETTER HEH DOCHASHMI
    [0679]			// ARABIC LETTER TTEH
    [0679,06BE]		// ARABIC LETTER TTEH   + ARABIC LETTER HEH DOCHASHMI
    [062B]			// ARABIC LETTER THEH
    [062C]			// ARABIC LETTER JEEM
    [062C,06BE]		// ARABIC LETTER JEEM   + ARABIC LETTER HEH DOCHASHMI
    [0686]			// ARABIC LETTER TCHEH
    [0686,06BE]		// ARABIC LETTER TCHEH  + ARABIC LETTER HEH DOCHASHMI
    [062D]			// ARABIC LETTER HAH
    [062E]			// ARABIC LETTER KHAH
    [062F]			// ARABIC LETTER DAL
    [062F,06BE]		// ARABIC LETTER DAL    + ARABIC LETTER HEH DOCHASHMI
    [0688]			// ARABIC LETTER DDAL
    [0688,06BE]		// ARABIC LETTER DDAL   + ARABIC LETTER HEH DOCHASHMI
    [0630]			// ARABIC LETTER THAL
    [0631]			// ARABIC LETTER REH
    [0631,06BE]		// ARABIC LETTER REH    + ARABIC LETTER HEH DOCHASHMI
    [0691]			// ARABIC LETTER RREH
    [0691,06BE]		// ARABIC LETTER RREH   + ARABIC LETTER HEH DOCHASHMI
    [0632]			// ARABIC LETTER ZAIN
    [0698]			// ARABIC LETTER JEH
    [0633]			// ARABIC LETTER SEEN
    [0634]			// ARABIC LETTER SHEEN
    [0635]			// ARABIC LETTER SAD
    [0636]			// ARABIC LETTER DAD
    [0637]			// ARABIC LETTER TAH
    [0638]			// ARABIC LETTER ZAH
    [0639]			// ARABIC LETTER AIN
    [063A]			// ARABIC LETTER GHAIN
    [0641]			// ARABIC LETTER FEH
    [0642]			// ARABIC LETTER QAF
    [06A9]			// ARABIC LETTER KAF
    [06A9,06BE]		// ARABIC LETTER KAF    + ARABIC LETTER HEH DOCHASHMI
    [06AF]			// ARABIC LETTER GAF
    [06AF,06BE]		// ARABIC LETTER GAF    + ARABIC LETTER HEH DOCHASHMI
    [0644]			// ARABIC LETTER LAM
    [0644,06BE]		// ARABIC LETTER LAM    + ARABIC LETTER HEH DOCHASHMI
    [0645]			// ARABIC LETTER MEEM
    [0645,06BE]		// ARABIC LETTER MEEM   + ARABIC LETTER HEH DOCHASHMI
    [0646]			// ARABIC LETTER NOON
    [0646,06BE]		// ARABIC LETTER NOON   + ARABIC LETTER HEH DOCHASHMI
    [06BA]			// ARABIC LETTER NOON GHUNNA
    [06BA,06BE]		// ARABIC LETTER NOON GHUNNA + ARABIC LETTER HEH DOCHASHMI
    [0648]			// ARABIC LETTER WAW
    [0624]			// ARABIC LETTER WAW WITH HAMZA ABOVE                           Added by Kashif
    [0648,06BE]		// ARABIC LETTER WAW    + ARABIC LETTER HEH DOCHASHMI
    [06C1]			// ARABIC LETTER HEH GOAL
    [06C2]			// ARABIC LETTER HEH GOAL WITH HAMZA ABOVE
    [06BE]			// ARABIC LETTER HEH DOCHASHMI
    [06C3]			// ARABIC LETTER TEH MARBUTA GOAL
    [0621]			// ARABIC LETTER HAMZA
    [0626]			// ARABIC LETTER YEH WITH HAMZA ABOVE
    [06CC]			// ARABIC LETTER FARSI YEH
    [06CC,06BE]		// ARABIC LETTER FARSI YEH +  ARABIC LETTER HEH DOCHASHMI
    [06D2]			// ARABIC LETTER YEH BARREE	

    */
    public class UrduComparer : IComparer<string> 
	{
        private const int ALEF = 0x627;
        private const int MADDAH = 0x653;
        private const int HEH_DOCHASHMI = 0x6BE;


        // Characters that compound with HEH DOCHASHMI and need special 
        // handling for sorting
        private static readonly int[] DOCHASHMI_CHARACTERS = { 
            0x628,		// ARABIC LETTER BEH    
            0x67E,		// ARABIC LETTER PEH    
            0x62A,		// ARABIC LETTER THE    
            0x679,		// ARABIC LETTER TTEH   
            0x62C,		// ARABIC LETTER JEEM   
            0x686,		// ARABIC LETTER TCHEH  
            0x62F,		// ARABIC LETTER DAL    
            0x688,		// ARABIC LETTER DDAL   
            0x631,		// ARABIC LETTER REH    
            0x691,		// ARABIC LETTER RREH   
            0x6A9,		// ARABIC LETTER KAF    
            0x6AF,		// ARABIC LETTER GAF    
            0x644,		// ARABIC LETTER LAM    
            0x645,		// ARABIC LETTER MEEM   
            0x646,		// ARABIC LETTER NOON   
            0x6BA,		// ARABIC LETTER NOON GHUNNA 
            0x648,		// ARABIC LETTER WAW    
            0x6CC		// ARABIC LETTER FARSI YEH 
        };

        // Simple collation order. This table can not correctly handle the 
        // dochashmi heh characters correctly by itself
        private static readonly int[] COLLATION_TABLE = { 
            0x200C,	// ZERO WIDTH NON-JOINER
            0x600,	// ARABIC NUMBER SIGN
            0x601,	// ARABIC SIGN SANAH
            0x602,	// ARABIC FOOTNOTE MARKER
            0x603,	// ARABIC SIGN SAFHA
            0x615,	// ARABIC SMALL HIGH TAH
            0x60C,	// ARABIC COMMA
            0x60D,	// ARABIC DATE SEPARATOR
            0x66B,	// ARABIC DECIMAL SEPARATOR
            0x66C,	// ARABIC THOUSANDS SEPARATOR
            0x61F,	// ARABIC QUESTION MARK
            0x61B,	// ARABIC SEMICOLON
            0x6D4,	// ARABIC FULL STOP
            0x66A,	// ARABIC PERCENT SIGN
            0x60E,	// ARABIC POETIC VERSE SIGN
            0x60F,	// ARABIC SIGN MISRA
            0x610,	// ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM
            0x611,	// ARABIC SIGN ALAYHE ASSALLAM
            0x613,	// ARABIC SIGN RADI ALLAHOU ANHU
            0x612,	// ARABIC SIGN RAHMATULLAH ALAYHE
            0x614,	// ARABIC SIGN TAKHALLUS
            0x652,	// ARABIC SUKUN
            0x64E,	// ARABIC FATHA
            0x650,	// ARABIC KASRA
            0x64F,	// ARABIC DAMMA
            0x670,	// ARABIC LETTER SUPERSCRIPT ALEF
            0x656,	// ARABIC SUBSCRIPT ALEF
            0x657,	// ARABIC INVERTED DAMMA 
            0x64B,	// ARABIC FATHATAN
            0x64D,	// ARABIC KASRATAN
            0x64C,	// ARABIC DAMMATAN
            0x654,	// ARABIC HAMZA ABOVE
            0x651,	// ARABIC SHADDA
            0x658,	// ARABIC MARK NOON GHUNNA
            0x653,	// ARABIC MADDAH ABOVE
            0x6F0,	// EXTENDED ARABIC-INDIC DIGIT ZERO
            0x6F1,	// EXTENDED ARABIC-INDIC DIGIT ONE
            0x6F2,	// EXTENDED ARABIC-INDIC DIGIT TWO
            0x6F3,	// EXTENDED ARABIC-INDIC DIGIT THREE
            0x6F4,	// EXTENDED ARABIC-INDIC DIGIT FOUR
            0x6F5,	// EXTENDED ARABIC-INDIC DIGIT FIVE
            0x6F6,	// EXTENDED ARABIC-INDIC DIGIT SIX
            0x6F7,	// EXTENDED ARABIC-INDIC DIGIT SEVEN
            0x6F8,	// EXTENDED ARABIC-INDIC DIGIT EIGHT
            0x6F9,	// EXTENDED ARABIC-INDIC DIGIT NINE
            0x627,	// ARABIC LETTER ALEF
            0x622,	// ARABIC LETTER ALEF WITH MADDA ABOVE
            0x623,  // ARABIC LETTER ALEF WITH HAMZA ABOVE                      Added by Kashif 
            0x628,	// ARABIC LETTER BEH
            0x67E,	// ARABIC LETTER PEH
            0x62A,	// ARABIC LETTER TEH
            0x679,	// ARABIC LETTER TTEH
            0x62B,	// ARABIC LETTER THEH
            0x62C,	// ARABIC LETTER JEEM
            0x686,	// ARABIC LETTER TCHEH
            0x62D,	// ARABIC LETTER HAH
            0x62E,	// ARABIC LETTER KHAH
            0x62F,	// ARABIC LETTER DAL
            0x688,	// ARABIC LETTER DDAL
            0x630,	// ARABIC LETTER THAL
            0x631,	// ARABIC LETTER REH
            0x691,	// ARABIC LETTER RREH
            0x632,	// ARABIC LETTER ZAIN
            0x698,	// ARABIC LETTER JEH
            0x633,	// ARABIC LETTER SEEN
            0x634,	// ARABIC LETTER SHEEN
            0x635,	// ARABIC LETTER SAD
            0x636,	// ARABIC LETTER DAD
            0x637,	// ARABIC LETTER TAH
            0x638,	// ARABIC LETTER ZAH
            0x639,	// ARABIC LETTER AIN
            0x63A,	// ARABIC LETTER GHAIN
            0x641,	// ARABIC LETTER FEH
            0x642,	// ARABIC LETTER QAF
            0x6A9,	// ARABIC LETTER KAF
            0x6AF,	// ARABIC LETTER GAF
            0x644,	// ARABIC LETTER LAM
            0x645,	// ARABIC LETTER MEEM
            0x646,	// ARABIC LETTER NOON
            0x6BA,	// ARABIC LETTER NOON GHUNNA
            0x648,	// ARABIC LETTER WAW
            0x624, 	// ARABIC LETTER WAW WITH HAMZA ABOVE                           Added by Kashif
            0x6C1,	// ARABIC LETTER HEH GOAL
            0x6C2,	// ARABIC LETTER HEH GOAL WITH HAMZA ABOVE
            0x6BE,	// ARABIC LETTER HEH DOCHASHMI
            0x6C3,	// ARABIC LETTER TEH MARBUTA GOAL
            0x621,	// ARABIC LETTER HAMZA
            0x626,	// ARABIC LETTER YEH WITH HAMZA ABOVE
            0x6CC,	// ARABIC LETTER FARSI YEH
            0x6D2	// ARABIC LETTER YEH BARREE	
        };

        private static Dictionary<int, int> _collationTable = null;
        private static Dictionary<int, int> _specialCharacters = null;
        
        
        public int Compare(string word1, string word2)
		{
            int secondChar;
            int length = Math.Min(word1.Length, word2.Length);
            char[] char1 = word1.ToCharArray(0, length);
            char[] char2 = word2.ToCharArray(0, length);

            for(int i = 0; i < length; i++)
            {
                if (char1[i] != char2[i])
                    return Compare(char1[i], char2[i]);
                else if (i < (length - 1))
                {
                    if (char1[i + 1] != char2[i + 1])
                    {
                        if (_specialCharacters.ContainsKey(char1[i]))
                        {
                            secondChar = _specialCharacters[char1[i]];
                            if (char1[i + 1] == secondChar)
                                return 1;   // word1 is greater
                            else if (char2[i + 1] == secondChar)
                                return -1;  // word1 is lesser 
                        }
                    }
                }
            }

            return word1.Length.CompareTo(word2.Length);
		}

        public int Compare(int char1, int char2)
		{
            int pos1, pos2;

            pos1 = _collationTable[char1];
            pos2 = _collationTable[char2];

            return pos1.CompareTo(pos2);
		}

        public void Init()
        {
            if (_collationTable == null)
                _collationTable = GetCollationTable();

            if (_specialCharacters == null)
                _specialCharacters = GetSpecialCharactersTable();
        }

        private Dictionary<int, int> GetCollationTable()
        {
            int code;
            Dictionary<int, int> table = new Dictionary<int, int>();

            for(int i = 0; i < COLLATION_TABLE.Length; i++)
            {
                code = COLLATION_TABLE[i];

                Debug.Assert(!table.ContainsKey(code), string.Format("Duplicate key found in collation table: {0:X}", code));

                if (!table.ContainsKey(code))
                    table.Add(code, i); 
            }

            foreach (int charCode in Globals.CRULP_APPROVED_CODES)
            {
                Debug.Assert(table.ContainsKey(charCode), string.Format("CRULP approved code {0:X} not found in collation table", charCode));
            }

            return table;
        }

        /// <summary>
        /// These are special character sequences. If the character in key is followed by the
        /// character code in value, the it should be considered one character which comes
        /// AFTER the character in key.
        /// </summary>
        /// <returns></returns>
        private Dictionary<int, int> GetSpecialCharactersTable()
        {
            Dictionary<int, int> table = new Dictionary<int, int>();

            // All characters that when combined with dochashmi heh are 
            // considered one character and this character comes AFTER
            foreach (int charCode in DOCHASHMI_CHARACTERS)
                table.Add(charCode, HEH_DOCHASHMI);

            // Alif Maddah is another special sequence
            table.Add(ALEF, MADDAH);

            return table;
        }

    }
}
